package com.fph.design.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName ClassLoaderUtils
 * @Description TODO
 * @Author fph
 * @Date 2024-07-10 9:35
 **/
public class ClassLoaderUtils {

    private static Set<Class> primitiveSet = new HashSet<>();

    static {
        primitiveSet.add(Integer.class);
        primitiveSet.add(Long.class);
        primitiveSet.add(Float.class);
        primitiveSet.add(Byte.class);
        primitiveSet.add(Short.class);
        primitiveSet.add(Double.class);
        primitiveSet.add(Character.class);
        primitiveSet.add(Boolean.class);
    }

    /**
     * 获取当前的classLoader
     * @return
     */
    public static ClassLoader getCurrentClassLoader() {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        if(classLoader == null){
            classLoader = ClassLoaderUtils.class.getClassLoader();
        }
        return classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
    }

    /**
     * 获取classLoader
     * @param clazz 某个类
     * @return
     */
    public static ClassLoader getClassLoader(Class<?> clazz) {
        ClassLoader calssLoader = Thread.currentThread().getContextClassLoader();
        if(calssLoader != null){
            return calssLoader;
        }
        if(clazz != null){
            calssLoader = clazz.getClassLoader();
            if(calssLoader != null){
                return calssLoader;
            }
            return clazz.getClassLoader();
        }
        return ClassLoader.getSystemClassLoader();
    }

    /**
     * 根据类名获取Class
     * @param className
     * @return
     * @throws ClassNotFoundException 找不到类
     */
    public static Class forName(String className) throws ClassNotFoundException {
        return forName(className, true);
    }

    /**
     * 根据类名获取Class
     * @param className 类名
     * @param initialize 是否初始化
     * @return
     * @throws ClassNotFoundException 找不到类
     */
    public static Class forName(String className, boolean initialize) throws ClassNotFoundException {
        return forName(className, initialize, getCurrentClassLoader());
    }

    /**
     * 根据类名获取Class
     * @param className 类名
     * @param initialize 是否初始化
     * @param classLoader 类加载器
     * @return
     * @throws ClassNotFoundException 找不到类
     */
    public static Class forName(String className, boolean initialize, ClassLoader classLoader) throws ClassNotFoundException{
        return Class.forName(className, true, classLoader);
    }

    /**
     * 实例化对象，（只检查默认的构造函数）
     * @param clazz 对象类
     * @return 对象实例
     * @param <T> 对象具体类
     * @throws Exception 没有找到方法，或者无法处理，或者初始化方法异常等
     */
    public static <T> T newInstance(Class<T> clazz) throws Exception {
        if(primitiveSet.contains(clazz)){
            return null;
        }
        // 非静态内部类
        // 是否是一个成员类（即在另一个类的内部定义的类，但不是静态的）
        // 检查 clazz 的修饰符中是否包含 static
        if(clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())){
            Constructor<?>[] constructors = clazz.getDeclaredConstructors();
            Constructor<?> constructor = null;
            for (Constructor<?> c : constructors){
                if (c.getParameterTypes().length == 1) {
                    constructor = c;
                    break;
                }
            }
            if(constructor != null){
                //是否可以访问
                if(constructor.isAccessible()){
                    return (T) constructor.newInstance(new Object[]{null});
                } else {
                    try {
                        constructor.setAccessible(true);
                        return (T) constructor.newInstance(new Object[]{null});
                    } finally {
                        constructor.setAccessible(false);
                    }
                }
            } else {
                throw new Exception("The " + clazz.getCanonicalName() + " has no default constructor!");
            }
        }
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            Constructor<T> constructor = clazz.getDeclaredConstructor();
            if (constructor.isAccessible()) {
                throw new Exception("The " + clazz.getCanonicalName() + " has no default constructor!", e);
            } else {
                try {
                    constructor.setAccessible(true);
                    return constructor.newInstance();
                } finally {
                    constructor.setAccessible(false);
                }
            }
        }
    }

    public static Class<?>[] getClazzByArgs(Object[] args) {
        Class<?>[] parameterTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ArrayList) {
                parameterTypes[i] = List.class;
                continue;
            }
            if (args[i] instanceof LinkedList) {
                parameterTypes[i] = List.class;
                continue;
            }
            if (args[i] instanceof HashMap) {
                parameterTypes[i] = Map.class;
                continue;
            }
            if (args[i] instanceof Long){
                parameterTypes[i] = long.class;
                continue;
            }
            if (args[i] instanceof Double){
                parameterTypes[i] = double.class;
                continue;
            }
            if (args[i] instanceof TimeUnit){
                parameterTypes[i] = TimeUnit.class;
                continue;
            }
            parameterTypes[i] = args[i].getClass();
        }
        return parameterTypes;
    }

    /**
     * 获取方法
     * @param classType
     * @param methodName 方法名称
     * @param parameterTypes  参数类型
     * @return
     * @throws NoSuchMethodException
     */
    public Method getMethod(Class<?> classType, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
        return classType.getMethod(methodName, parameterTypes);
    }
}

